#pragma once
#include <exception>

#include "../inc_windows_h.hpp"
#include "basic_allocator.hpp"

namespace wxx
{
	template<class T>
	struct heap_allocator : basic_allocator<T>
	{
		WXX_memory_allocator_rebind(heap_allocator);

		explicit heap_allocator(HANDLE heap = ::GetProcessHeap())
			: m_heap(heap)
		{
		}

		explicit heap_allocator(const heap_allocator& other)
			: m_heap(other.m_heap)
		{
		}

		template<class U>
		explicit heap_allocator(const heap_allocator<U>& other)
			: m_heap(other.m_heap)
		{
		}

		HANDLE handle() const
		{
			return m_heap;
		}

		pointer allocate(size_type count) const
		{
			pointer ptr = reinterpret_cast<pointer>(
				::HeapAlloc(m_heap, 0, count * sizeof(T))
			);

			if (!ptr)
			{
				throw std::bad_alloc();
			}

			return ptr;
		}

		void deallocate(pointer ptr) const
		{
			if (ptr)
			{
				::HeapFree(m_heap, 0, ptr);
			}
		}

		void deallocate(pointer ptr, size_type) const
		{
			return deallocate(ptr);
		}

	private:
		const HANDLE m_heap;
	};

	template<class T, class U>
	bool operator == (const heap_allocator<T>& x,
		              const heap_allocator<U>& y)
	{
		return x.handle() == y.handle();
	}

	template<class T, class U>
	bool operator != (const heap_allocator<T>& x,
				      const heap_allocator<U>& y)
	{
		return !(x == y);
	}
};